package com.car.framework;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map.Entry;
import android.os.Handler;
import android.os.Message;

import com.car.comm.DuplexMap;
import com.car.comm.ErrorAgent;
import com.car.comm.Logger;
import com.car.comm.Variable;
import com.car.datalayer.http.CHttpRequest;
import com.car.datalayer.http.CHttpResponse;
import com.car.datalayer.http.IHttpEngine;
import com.car.datalayer.http.IHttpResponseHandler;
import com.car.datalayer.http.RequestId;
import com.car.postoffice.CAddress;
import com.car.postoffice.CMail;
import com.car.postoffice.CMailResult;
import com.car.postoffice.ITransferWorker;
import com.car.postoffice.PostOffice;
import com.car.postoffice.SendException;
import com.car.postoffice.TPostMark;

class CHttpAdaptor implements ITransferWorker, IHttpResponseHandler{
	private static final int HTTP_RESPONSE = 100;
	private class HttpMessage{
		public RequestId reqId;
		public int innerErrorCode;
		public CHttpResponse resp;
		public Serializable respObj;
		
		public HttpMessage(RequestId reqId, 
				           int innerErrorCode,
				           CHttpResponse resp,
				           Serializable respObj){
			this.reqId = reqId;
			this.innerErrorCode = innerErrorCode;
			this.resp = resp;
			this.respObj = respObj;
		}
	}
	
	private Handler messageHandler;
	private PostOffice office;
	private IHttpEngine engine;
	private DuplexMap<RequestId, TPostMark> records;
	
	public CHttpAdaptor(PostOffice office, IHttpEngine engine){
		this.office = office;
		this.engine = engine;
		this.records = new DuplexMap<RequestId, TPostMark>();
				
		this.messageHandler = new Handler(){
			@Override
			public void handleMessage(Message msg) {
				switch(msg.what){
				case HTTP_RESPONSE:{
					HttpMessage httpMsg = (HttpMessage)msg.obj;
					TPostMark mark = CHttpAdaptor.this.records.getByKey(httpMsg.reqId);
					if(mark == null){
						return ;
					}
					CMailResult result = new CMailResult(httpMsg.innerErrorCode, 
											ErrorAgent.GetInnerErrorMsg(httpMsg.innerErrorCode));
					if(httpMsg.innerErrorCode == 0 && httpMsg.resp.getStatusCode() != 200){
						result.setErrorCode(ErrorAgent.EHttpStatusNotOK);
						result.setErrorMsg("STATUSCODE=" + httpMsg.resp.getStatusCode());
					}
					
					if(httpMsg.respObj != null){
						CHttpAdaptor.this.office.ReplyMail(mark, result, 
								null, httpMsg.respObj);
					}else{
						CHttpAdaptor.this.office.ReplyMail(mark, result,
								httpMsg.resp.getResponseBody(), null);
					}
					
					records.remove(httpMsg.reqId);
				} break;
				}
			}
		};
	}
	
	@Override
	public void HandleMail(TPostMark mark, CMail mail, int level) throws SendException {
		HashMap<String,String> parameters = mail.getHeader().getParameters();
		CAddress dstAddr = mail.getEnvelope().getDstAddr();
		int method = CHttpRequest.EHttpInvalid;
		if(dstAddr.getScheme().equals(Variable.httpGetScheme)){
			method = CHttpRequest.EHttpGet;
		}else{
			method = CHttpRequest.EHttpPost;
		}
		
		CHttpRequest req = new CHttpRequest(method);
		req.setUri("http://" + dstAddr.getPath());
		for(Entry<String, String> entry : parameters.entrySet()){
			req.setHeader(entry.getKey(), entry.getValue());
		}
		
		req.setPostContent(mail.getMailContent());
		
		RequestId reqId = engine.SendRequest(level, req, this);
		records.put(reqId, mark);
	}

	@Override
	public void Cancel(TPostMark mark) {
		RequestId reqId = this.records.getbyValue(mark);
		if(reqId != null){
			engine.Cancel(reqId);
			records.remove(reqId);
		}
	}

	@Override
	public void CancelAll() {
		engine.CancelAll();
		records.clear();
	}

	@Override
	public void Response(RequestId reqId, 
						 int innerErrorCode,
						 CHttpResponse response) {
		TPostMark mark = this.records.getByKey(reqId);
		if(mark == null){
			// 正在回复的过程中被cancel掉, 那么直接返回
			Logger.LogRun("Adaptor response get null post mark");
			return ;
		}
		Serializable respObj = null;
		if(innerErrorCode == 0 &&
		   response.getStatusCode() == 200 &&
		   mark.getMapping() != null &&
		   response.getResponseBody().length > 0){
			respObj = mark.getMapping().Mapping(response.getResponseBody());
			if(respObj == null){
				innerErrorCode = ErrorAgent.EDataMappingFailed;
			}
		}
		
		HttpMessage msgObj = new HttpMessage(reqId, innerErrorCode, response, respObj);
		Message msg = messageHandler.obtainMessage(HTTP_RESPONSE, msgObj);
		if(!messageHandler.sendMessage(msg)){
			Logger.LogErr("SendMessage Failed [RequestId=" + reqId + "]");
		}
	}

}
